package me.zhengjie.tool;



import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by TQ ThinkPad on 2020/3/12.
 */
public class MyMap<K, V> extends HashMap {

    private static final long serialVersionUID = 5984672285326340211L;

    public MyMap() {
        //
    }

    public MyMap(Map map) {
        super.putAll(map);
    }

    public MyMap lowerCaseKeyMap() {
        //todo
        MyMap convertMap = new MyMap();
        String newKey = "";
        Object newObj = null;
        for (Object key : this.keySet()) {
            newKey = ((String) key).toLowerCase();
            newObj = this.get(key);
            convertMap.put(newKey, newObj);
        }
        return convertMap;
    }

    public MyMap putValue(Object k, Object v) {
        this.put(k, v);
        return this;
    }

//    public Map<byte[], byte[]> putByte(String k, String v) {
//        Map<byte[], byte[]> map = new HashMap<byte[], byte[]>();
//        map.put(k.getBytes(), v.getBytes());
//        return map;
//    }

    public Integer getAsInteger(String key) {
        Object obj = this.get(key);
        return !ValidateUtil.isEmpty(obj) ? new Integer(obj.toString()) : null;
    }

    public Long getAsLong(String key) {
        Object obj = this.get(key);
        return !ValidateUtil.isEmpty(obj) ? new Long(obj.toString()) : null;
    }

    public String getAsString(String key) {
        Object obj = this.get(key);
        return obj != null ? obj.toString()  : "";
    }

    public BigDecimal getAsBigDecimal(String key) {
        Object obj = this.get(key);
        return !ValidateUtil.isEmpty(obj)  ? new BigDecimal(obj.toString()) : null;
    }

    /**
     * null返回0
     * @param key
     * @return
     */
    public BigDecimal getAsBigDecimalNullToZero(String key) {
        Object obj = this.get(key);
        if ("".equals(obj)){
            return BigDecimal.ZERO;
        }
        return obj != null ? new BigDecimal(obj.toString()) : BigDecimal.ZERO;
    }


    /**
     * 只有存入时是Boolean,才可使用此方法取值
     * 当MaMap中不存在key时，返回false
     *
     * @param key
     * @return
     */
    public Boolean getAsBoolean(String key) {
        Object obj = this.get(key);
        return obj != null ? (Boolean) obj : false;
    }

    /**
     * 将MyMap转换成domain
     *
     * @param dto
     * @param cla
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> T convertToDomain(MyMap dto, Class<T> cla) {
        try {
            Object obj = cla.newInstance();
            if (ValidateUtil.isEmpty(dto)) {
                return (T) obj;
            }
            Field[] fields = cla.getDeclaredFields();
            String fieldName, typeName;
            Method method;
            Object value;
            for (Field field : fields) {
                fieldName = field.getName();
                if (ValidateUtil.isEmpty(dto.get(fieldName))) {
                    continue;
                }
                typeName = field.getType().getName();
                try {
                    method = cla.getDeclaredMethod("set" + fieldName.substring(0, 1).toUpperCase() +
                            fieldName.substring(1, fieldName.length()), field.getType());
                } catch (NoSuchMethodException e) {
                    continue;
                }

                if ("java.lang.String".equals(typeName)) {
                    value = dto.getAsString(fieldName);
                } else if ("java.lang.Long".equals(typeName)) {
                    value = dto.getAsLong(fieldName);
                } else if ("java.lang.Integer".equals(typeName)) {
                    value = dto.getAsInteger(fieldName);
                } else if ("java.lang.Double".equals(typeName)) {
                    value = dto.getAsBigDecimal(fieldName).doubleValue();
                } else if ("java.util.Date".equals(typeName)) {
                    value = dto.getAsString(fieldName);
                    value = new SimpleDateFormat("yyyy-MM-dd").parse((String) value);
                } else if ("java.sql.Date".equals(typeName)) {
                    value = dto.getAsString(fieldName);
                    value = new java.sql.Date(new SimpleDateFormat("yyyy-MM-dd").parse((String) value).getTime());
                } else if ("java.math.BigDecimal".equals(typeName)) {
                    value = dto.getAsBigDecimal(fieldName);
                } else {
                    value = convertToDomain(convertToMap(dto.get(fieldName)), Class.forName(typeName));
                }
                method.invoke(obj, value);

            }
            return (T) obj;
        } catch (Exception e) {
            throw new IllegalArgumentException(e.getMessage());
        }

    }

    /**
     * 将domain转换成map
     *
     * @param domain
     * @return
     * @throws Exception
     */
    public static MyMap convertToMap(Object domain) {
        try {
            Map<String, Object> map = new HashMap<>();
            Class cla = domain.getClass();
            Field[] fields = cla.getDeclaredFields();
            String fieldName;
            Method method;
            for (Field field : fields) {
                fieldName = field.getName();
                try {
                    method = cla.getDeclaredMethod("get" + fieldName.substring(0, 1).toUpperCase() +
                            fieldName.substring(1, fieldName.length()));
                } catch (NoSuchMethodException e) {
                    continue;
                }
                map.put(fieldName.toLowerCase(), method.invoke(domain));
            }
            MyMap myMap = new MyMap();
            myMap.putAll(map);
            return myMap;

        } catch (Exception e) {
            throw new IllegalArgumentException(e.getMessage());
        }
    }


}
